package eu.jk.web.template;

import java.lang.reflect.Method;
import java.util.Collection;
import java.util.Map;


public class Filler {

	/**
	 * 填充模板
	 * @throws ErrorInstruction 错误的指令
	 */
	public static String fill(String template,Map<String,Object> parameters) throws ErrorInstruction{
		TemplatePara para=new Parameters();
		para.addAll(parameters);
		return fillTemplate(template, para, null);
	}
	
	/**
	 * 填充模板
	 * @throws ErrorInstruction 错误的指令
	 */
	public static String fill(String template,TemplatePara parameters) throws ErrorInstruction{
		return null;
	}
	
	private static String fillTemplate(String template,TemplatePara parameters,
			TemplatePara tempParameters) throws ErrorInstruction{
		int index=0;
		int deep=0;
		StringBuffer buff=new StringBuffer(template);
		StringBuffer stack=new StringBuffer();
		String ins=null;
		//遍历模板，寻找指令
		while((index=buff.indexOf("$["))>=0){
			stack.append(buff.substring(0, index));
			buff.delete(0, index+2);
			deep=1;
			index=0;
			while(deep>0){
				char c=buff.charAt(index);
				if(c==']'&&buff.charAt(index-1)!='\\')
					deep--;
				if(c=='$'&&buff.charAt(index+1)=='[')
					deep++;
				index++;
			}
			index--;
			ins=buff.substring(0, index);
			//将指令字符串传递给处理函数，获取返回值
			Object result=doInstruction(ins, parameters,tempParameters);
			if(result!=null)
				stack.append(result.toString());
			buff.delete(0, index+1);
		}
		stack.append(buff.toString());
		return stack.toString();
	}
	
	/**
	 * 指令分配器,将指令分配给各处理函数.
	 */
	private static Object doInstruction(String ins,
			TemplatePara parameters, TemplatePara tempParameters)
					throws ErrorInstruction {
		if(ins==null)
			return null;
		try {
			//loop,循环体
			if(ins.startsWith("loop"))
				return doLoop(ins.replaceFirst("loop:", ""), parameters,tempParameters);
			//处理数据实体
			return doEntity(ins, parameters,tempParameters);
		} catch (ErrorInstruction e) {
			throw new ErrorInstruction(ins);
		}
		
	}
	
	/**
	 * 处理数据实体,临时实体将优于全局实体
	 */
	private static Object doEntity(String ins, TemplatePara parameters, 
			TemplatePara tempParameters) throws ErrorInstruction{
		ins=ins.replace(" ", "");
		String[] fields=ins.split("\\.");
		Object entity=null;
		//获取实体
		if(tempParameters!=null)
			entity=tempParameters.get(fields[0]);
		if(entity==null)
			entity=parameters.get(fields[0]);
		if(entity==null)
			return null;
		//迭代获取字段
		for(int i=1;i<fields.length;i++){
			try {
				entity=getValue(entity,fields[i]);
			} catch (ErrorInstruction e) {
				throw new ErrorInstruction(ins);
			}
		}
		return entity;
	}

	/**
	 * 获取实体字段
	 */
	private static Object getValue(Object object,String fields) throws ErrorInstruction{
		Class<?> _class=object.getClass();
		Method method=null;
		fields=fields.trim();
		//使用get方法获取内部变量
		String methodName="get"+String.valueOf(fields.charAt(0)).toUpperCase()+fields.substring(1);
		try {
			method=_class.getMethod(methodName);
			return method.invoke(object);
		} catch (Exception e) {
			throw new ErrorInstruction(fields);
		} 
	}
	
	/**
	 * 处理列表循环体
	 */
	private static String doLoop(String ins, TemplatePara parameters, TemplatePara tempParameters) throws ErrorInstruction {
		//列表名
		String items_ins=ins.substring(0,ins.indexOf(':'));
		ins=ins.replaceFirst(items_ins+":", "");
		items_ins=items_ins.replace(" ", "");
		//列表变量名
		String var_ins=ins.substring(0,ins.indexOf(';'));
		ins=ins.replaceFirst(var_ins+";", "");
		var_ins=var_ins.replace(" ", "");
		Object items=null;
		try {
			items=doEntity(items_ins, parameters,tempParameters);
		} catch (ErrorInstruction e) {
			throw new ErrorInstruction(ins);
		}
		if(!(items instanceof Collection<?>))
			throw new ErrorInstruction(ins);
		StringBuffer buff=new StringBuffer();
		if(tempParameters==null)
			tempParameters=new Parameters();
		for(Object o:(Collection<?>)items){
			tempParameters.set(var_ins, o);
			try {
				buff.append(fillTemplate(ins, parameters,tempParameters));
			} catch (ErrorInstruction e) {
				throw new ErrorInstruction(ins);
			}
			tempParameters.remove(var_ins);
		}
		return buff.toString();
	}

}
